# -*- coding: utf-8 -*-

# tests/test_argparse_help.py
# Part of ‘manpage’, a Python library for making Unix manual documents.
#
# Copyright © 2015–2016 Ben Finney <ben+python@benfinney.id.au>
#
# This is free software: see the grant of license at end of this file.

""" Unit tests for ArgumentParser help integration. """

import sys
import os
import os.path
import argparse
import textwrap
import unittest
import unittest.mock

__package__ = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
__import__(__package__)
sys.path.insert(1, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import manpage.argparse_help


def setup_formatter_instance(testcase, test_class=None, test_args=None):
    """ Set up a `HelpFormatter` instance. """
    if test_class is None:
        test_class = testcase.formatter_class
    if test_args is None:
        test_args = testcase.test_args
    testcase.test_formatter_instance = test_class(**test_args)


class ManPageHelpFormatter_TestCase(unittest.TestCase):
    """ Test cases for class `ManPageHelpFormatter`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('simple', {
                'test_args': {
                    'prog': "lorem",
                    },
                'expected_class': formatter_class,
                'expected_command_name': "\\fBlorem\\fP",
                }),
            ('command-hyphenated', {
                'test_args': {
                    'prog': "lorem-ipsum",
                    },
                'expected_class': formatter_class,
                'expected_command_name': "\\fBlorem\\-ipsum\\fP",
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

    def test_instantiate(self):
        """ An instance should be created. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(self, test_args=scenario['test_args'])
                self.assertIsInstance(
                        self.test_formatter_instance,
                        self.formatter_class)

    def test_has_specified_command_name_markup(self):
        """ Should have the correct markup for the specified command name. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(self, test_args=scenario['test_args'])
                self.assertEqual(
                        self.test_formatter_instance._prog,
                        scenario['expected_command_name'])

    def test_indent_has_no_effect_on_level(self):
        """ Method `_indent` should have no effect on `_level`. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(self, test_args=scenario['test_args'])
                instance = self.test_formatter_instance
                prior_level = instance._level
                instance._indent()
                self.assertEqual(instance._level, prior_level)

    def test_indent_has_no_effect_on_current_indent(self):
        """ Method `_indent` should have no effect on `_current_indent`. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(self, test_args=scenario['test_args'])
                instance = self.test_formatter_instance
                prior_current_indent = instance._current_indent
                self.test_formatter_instance._indent()
                self.assertEqual(
                        instance._current_indent, prior_current_indent)

    def test_dedent_has_no_effect_on_level(self):
        """ Method `_dedent` should have no effect on `_level`. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(self, test_args=scenario['test_args'])
                instance = self.test_formatter_instance
                prior_level = instance._level
                instance._dedent()
                self.assertEqual(instance._level, prior_level)

    def test_dedent_has_no_effect_on_current_indent(self):
        """ Method `_dedent` should have no effect on `_current_indent`. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(self, test_args=scenario['test_args'])
                instance = self.test_formatter_instance
                prior_current_indent = instance._current_indent
                self.test_formatter_instance._dedent()
                self.assertEqual(
                        instance._current_indent, prior_current_indent)

    def test_split_lines_returns_all_content_in_one_item(self):
        """ Method `_split_lines` should return all content as one item. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(self, test_args=scenario['test_args'])
                test_text = textwrap.dedent("""\
                        Lorem ipsum,
                        dolor sit amet.
                        """)
                test_args = {
                        'text': test_text,
                        'width': 10,
                        }
                result = self.test_formatter_instance._split_lines(**test_args)
                expected_result = [test_text]
                self.assertEqual(result, expected_result)

class ManPageHelpFormatter_format_literal_text_TestCase(unittest.TestCase):
    """ Test cases for method `ManPageHelpFormatter._format_literal_text`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('simple', {
                'test_text': "Lorem ipsum",
                'expected_result': "\\fBLorem ipsum\\fP",
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

        setup_formatter_instance(self, test_args={
                'prog': "xyzzy",
                })

    def test_returns_expected_markup_text(self):
        """ Should return expected markup text. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                result = self.test_formatter_instance._format_literal_text(
                        scenario['test_text'])
                self.assertEqual(result, scenario['expected_result'])


class ManPageHelpFormatter_format_variable_text_TestCase(unittest.TestCase):
    """ Test cases for method `ManPageHelpFormatter._format_variable_text`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('simple', {
                'test_text': "Lorem ipsum",
                'expected_result': "\\fILorem ipsum\\fP",
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

        setup_formatter_instance(self, test_args={
                'prog': "xyzzy",
                })

    def test_returns_expected_markup_text(self):
        """ Should return expected markup text. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                result = self.test_formatter_instance._format_variable_text(
                        scenario['test_text'])
                self.assertEqual(result, scenario['expected_result'])


class ManPageHelpFormatter_format_option_text_TestCase(unittest.TestCase):
    """ Test cases for method `ManPageHelpFormatter._format_option_text`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('simple', {
                'test_text': "lorem",
                'expected_result': "lorem",
                }),
            ('leading-hyphen-one', {
                'test_text': "-l",
                'expected_result': "\\-l",
                }),
            ('leading-hyphen-two', {
                'test_text': "--lorem",
                'expected_result': "\\-\\-lorem",
                }),
            ('leading-hyphen-two,hyphenated', {
                'test_text': "--lorem-ipsum",
                'expected_result': "\\-\\-lorem\\-ipsum",
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

        setup_formatter_instance(self, test_args={
                'prog': "xyzzy",
                })

    def test_returns_expected_markup_text(self):
        """ Should return expected markup text. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                result = self.test_formatter_instance._format_option_text(
                        scenario['test_text'])
                self.assertEqual(result, scenario['expected_result'])


class ManPageHelpFormatter_format_usage_TestCase(unittest.TestCase):
    """ Test cases for method `ManPageHelpFormatter._format_usage`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('simple', {
                'test_formatter_args': {
                    'prog': "xyzzy",
                    },
                'test_args': {
                    'usage': None,
                    'actions': [],
                    'groups': [],
                    'prefix': None,
                    },
                }),
            ('prefix-specified', {
                'test_formatter_args': {
                    'prog': "xyzzy",
                    },
                'test_args': {
                    'usage': None,
                    'actions': [],
                    'groups': [],
                    'prefix': "Dolor sit amet",
                    },
                }),
            ('usage-specified', {
                'test_formatter_args': {
                    'prog': "xyzzy",
                    },
                'test_args': {
                    'usage': "Lorem ipsum",
                    'actions': [],
                    'groups': [],
                    'prefix': None,
                    },
                }),
            ('usage-specified,prefix-specified', {
                'test_formatter_args': {
                    'prog': "xyzzy",
                    },
                'test_args': {
                    'usage': "Lorem ipsum",
                    'actions': [],
                    'groups': [],
                    'prefix': "Dolor sit amet",
                    },
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

    def test_usage_message_contains_specified_usage_text(self):
        """ Usage text should contain the specified `usage`. """
        for (scenario_name, scenario) in (
                (scenario_name, scenario)
                for (scenario_name, scenario) in self.scenarios
                if scenario['test_args']['usage'] is not None):
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(
                        self, test_args=scenario['test_formatter_args'])
                result = self.test_formatter_instance._format_usage(
                        **scenario['test_args'])
                expected_text = scenario['test_args']['usage']
                self.assertIn(expected_text, result)

    def test_usage_message_omits_prefix(self):
        """ Usage text should omit any “usage” prefix. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(
                        self, test_args=scenario['test_formatter_args'])
                result = self.test_formatter_instance._format_usage(
                        **scenario['test_args'])
                self.assertFalse(result.lower().startswith("usage"))

    def test_usage_message_omits_specified_prefix(self):
        """ Usage text should omit the specified `prefix`. """
        for (scenario_name, scenario) in (
                (scenario_name, scenario)
                for (scenario_name, scenario) in self.scenarios
                if scenario['test_args']['prefix'] is not None):
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(
                        self, test_args=scenario['test_formatter_args'])
                result = self.test_formatter_instance._format_usage(
                        **scenario['test_args'])
                unwanted_prefix = scenario['test_args']['prefix']
                self.assertFalse(result.lower().startswith(unwanted_prefix))


class ManPageHelpFormatter_metavar_formatter_TestCase(unittest.TestCase):
    """ Test cases for `ManPageHelpFormatter._metavar_formatter`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('simple', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        ),
                    'default_metavar': "LOREM",
                    },
                'test_formatter_args': {
                    'tuple_size': 1,
                    },
                'expected_return_value': tuple(["\\fISPAM\\fP"]),
                }),
            ('simple,size-4', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        ),
                    'default_metavar': "LOREM",
                    },
                'test_formatter_args': {
                    'tuple_size': 4,
                    },
                'expected_return_value': tuple(["\\fISPAM\\fP"] * 4),
                }),
            ('metavar-specified,choices', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        choices=["SPAM","EGGS","BEANS"],
                        dest="spam", metavar="SPAM",
                        ),
                    'default_metavar': "LOREM",
                    },
                'test_formatter_args': {
                    'tuple_size': 1,
                    },
                'expected_return_value': tuple(["\\fISPAM\\fP"]),
                }),
            ('metavar-missing,choices', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        choices=["SPAM","EGGS","BEANS"],
                        dest="spam",
                        ),
                    'default_metavar': "LOREM",
                    },
                'test_formatter_args': {
                    'tuple_size': 1,
                    },
                'expected_return_value': tuple([
                    "{\\fBSPAM\\fP,\\fBEGGS\\fP,\\fBBEANS\\fP}"]),
                }),
            ('metavar-missing,choices,size-4', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        choices=["SPAM","EGGS","BEANS"],
                        dest="spam",
                        ),
                    'default_metavar': "LOREM",
                    },
                'test_formatter_args': {
                    'tuple_size': 4,
                    },
                'expected_return_value': tuple(
                    ["{\\fBSPAM\\fP,\\fBEGGS\\fP,\\fBBEANS\\fP}"] * 4),
                }),
            ('metavar-missing,default-metavar', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam",
                        ),
                    'default_metavar': "LOREM",
                    },
                'test_formatter_args': {
                    'tuple_size': 1,
                    },
                'expected_return_value': tuple(["\\fILOREM\\fP"]),
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

        setup_formatter_instance(self, test_args={
                'prog': "xyzzy",
                })

    def test_returns_function_that_produces_expected_value(self):
        """ Should return function that produces expected value. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                instance = self.test_formatter_instance
                formatter_func = instance._metavar_formatter(
                        **scenario['test_args'])
                result = formatter_func(**scenario['test_formatter_args'])
                self.assertEqual(result, scenario['expected_return_value'])


class ManPageHelpFormatter_format_args_TestCase(unittest.TestCase):
    """ Test cases for `ManPageHelpFormatter._format_args`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('nargs-missing', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        ),
                    'default_metavar': "LOREM",
                    },
                'metavar_markup': "\\fISPAM\\fP",
                'expected_result': "\\fISPAM\\fP",
                }),
            ('nargs-one', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        nargs=1,
                        ),
                    'default_metavar': "LOREM",
                    },
                'metavar_markup': "\\fISPAM\\fP",
                'expected_result': "\\fISPAM\\fP",
                }),
            ('nargs-three', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        nargs=3,
                        ),
                    'default_metavar': "LOREM",
                    },
                'metavar_markup': "\\fISPAM\\fP",
                'expected_result': "\\fISPAM\\fP \\fISPAM\\fP \\fISPAM\\fP",
                }),
            ('nargs-optional', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        nargs="?",
                        ),
                    'default_metavar': "LOREM",
                    },
                'metavar_markup': "\\fISPAM\\fP",
                'expected_result': "[\\fISPAM\\fP]",
                }),
            ('nargs-zero-or-more', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        nargs="*",
                        ),
                    'default_metavar': "LOREM",
                    },
                'metavar_markup': "\\fISPAM\\fP",
                'expected_result': "[\\fISPAM\\fP [\\fISPAM\\fP ...]]",
                }),
            ('nargs-one-or-more', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        nargs="+",
                        ),
                    'default_metavar': "LOREM",
                    },
                'metavar_markup': "\\fISPAM\\fP",
                'expected_result': "\\fISPAM\\fP [\\fISPAM\\fP ...]",
                }),
            ('nargs-remainder', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        nargs="...",
                        ),
                    'default_metavar': "LOREM",
                    },
                'metavar_markup': "\\fISPAM\\fP",
                'expected_result': "...",
                }),
            ('nargs-subcommand', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        nargs="A...",
                        ),
                    'default_metavar': "LOREM",
                    },
                'metavar_markup': "\\fISPAM\\fP",
                'expected_result': "\\fISPAM\\fP ...",
                }),
           ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

        setup_formatter_instance(self, test_args={
                'prog': "xyzzy",
                })

        self.patch_metavar_formatter()

    def patch_metavar_formatter(self):
        """ Patch the `_metavar_formatter` method. """
        func_patcher = unittest.mock.patch.object(
                self.test_formatter_instance, '_metavar_formatter',
                autospec=True)
        func_patcher.start()
        self.addCleanup(func_patcher.stop)

    def make_metavar_formatter(self, item_value):
        """ Make a fake metavar formatter function. """
        def formatter(tuple_size):
            result = tuple([item_value] * tuple_size)
            return result

        return formatter

    def test_returns_expected_markup_text(self):
        """ Should return expected markup text. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                instance = self.test_formatter_instance
                formatter_func = self.make_metavar_formatter(scenario[
                        'metavar_markup'])
                instance._metavar_formatter.return_value = formatter_func
                result = self.test_formatter_instance._format_args(
                        **scenario['test_args'])
                self.assertEqual(result, scenario['expected_result'])


class ManPageHelpFormatter_format_action_invocation_TestCase(unittest.TestCase):
    """ Test cases for `ManPageHelpFormatter.format_action_invocation`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('optional-action,boolean', {
                'test_args': {
                    'action': argparse._StoreTrueAction(
                        ["-d", "--dolor"],
                        dest="spam",
                        ),
                    },
                'expected_result': textwrap.dedent("""\

                    \\fB\\-d\\fP,
                    \\fB\\-\\-dolor\\fP"""),
                }),
            ('optional-action,nargs-one', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        ),
                    },
                'expected_result': textwrap.dedent("""\

                    \\fB\\-d\\fP \\fISPAM\\fP,
                    \\fB\\-\\-dolor\\fP \\fISPAM\\fP"""),
                }),
            ('optional-action,nargs-optional', {
                'test_args': {
                    'action': argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        nargs="?",
                        ),
                    },
                'expected_result': textwrap.dedent("""\

                    \\fB\\-d\\fP [\\fISPAM\\fP],
                    \\fB\\-\\-dolor\\fP [\\fISPAM\\fP]"""),
                }),
            ('positional-action', {
                'test_args': {
                    'action': argparse.Action(
                        option_strings=[],
                        dest="spam", metavar="SPAM",
                        ),
                    },
                'expected_result': textwrap.dedent("""\

                    \\fISPAM\\fP"""),
                }),
            ('positional-action,metavar-missing', {
                'test_args': {
                    'action': argparse.Action(
                        option_strings=[],
                        dest="spam",
                        ),
                    },
                'expected_result': textwrap.dedent("""\

                    \\fISPAM\\fP"""),
                }),
            ('positional-action,nargs-optional', {
                'test_args': {
                    'action': argparse.Action(
                        option_strings=[],
                        dest="spam",
                        nargs="?",
                        ),
                    },
                'expected_result': textwrap.dedent("""\

                    \\fISPAM\\fP"""),
                }),
            ('positional-action,nargs-three', {
                'test_args': {
                    'action': argparse.Action(
                        option_strings=[],
                        dest="spam",
                        nargs=3,
                        ),
                    },
                'expected_result': textwrap.dedent("""\

                    \\fISPAM\\fP"""),
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

        setup_formatter_instance(self, test_args={
                'prog': "xyzzy",
                })

    def test_returns_expected_markup_text(self):
        """ Should return expected markup text. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                instance = self.test_formatter_instance
                result = instance._format_action_invocation(
                        **scenario['test_args'])
                self.assertEqual(result, scenario['expected_result'])


class TestArgumentParser(argparse.ArgumentParser):
    """ Argument parser to test help formatting. """


def setup_parser_instance(
        testcase, test_class=None, test_args=None, test_actions=None):
    """ Set up an `ArgumentParser` instance. """
    if test_class is None:
        test_class = testcase.parser_class
    if test_args is None:
        test_args = testcase.test_args
    testcase.test_parser_instance = test_class(**test_args)
    if test_actions is None:
        test_actions = testcase.parser_actions
    for action in test_actions:
        testcase.test_parser_instance._add_action(action)


class ManPageHelpFormatter_format_options_TestCase(unittest.TestCase):
    """ Test cases for method `ManPageHelpFormatter.format_options`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter
    parser_class = argparse.ArgumentParser

    scenarios = [
            ('simple', {
                'test_args': {
                    'prog': "lorem",
                    },
                'parser_actions': [
                    argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        ),
                    ],
                'expected_result': textwrap.dedent("""\
                    optional arguments:
                      -h, --help            show this help message and exit
                      -d SPAM, --dolor SPAM
                    """)
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

    def test_returns_expected_markup(self):
        """ Should return the expected text markup for the inputs. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(self, test_args=scenario['test_args'])
                setup_parser_instance(
                        self,
                        test_args={},
                        test_actions=scenario['parser_actions'])
                result = self.test_formatter_instance.format_options(
                        self.test_parser_instance)
                self.assertEqual(scenario['expected_result'], result)


class ManPageHelpFormatter_start_section_TestCase(unittest.TestCase):
    """ Test cases for method `ManPageHelpFormatter.start_section`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter

    scenarios = [
            ('simple', {
                'test_formatter_args': {
                    'prog': "lorem",
                    },
                'test_current_section_args': {
                    'parent': None,
                    'heading': "Lorem Ipsum",
                    },
                'test_heading_text': "Dolor Sit Amet",
                'expected_heading_markup': textwrap.dedent("""\
                    .
                    .SS Dolor Sit Amet"""),
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

    def set_current_section(self, scenario):
        """ Make a formatter section to be the parent section. """
        section = self.formatter_class._Section(
                formatter=self,
                parent=scenario['test_current_section_args']['parent'],
                heading=scenario['test_current_section_args']['heading'])
        self.test_formatter_instance._current_section = section

    def test_sets_expected_heading_markup(self):
        """ Should set the expected text markup for the heading. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(
                        self, test_args=scenario['test_formatter_args'])
                self.set_current_section(scenario)
                self.test_formatter_instance.start_section(
                        scenario['test_heading_text'])
                self.assertEqual(
                        self.test_formatter_instance._current_section.heading,
                        scenario['expected_heading_markup'])

    def test_sets_expected_parent_section(self):
        """ Should set the expected parent section. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                setup_formatter_instance(
                        self, test_args=scenario['test_formatter_args'])
                self.set_current_section(scenario)
                expected_parent_section = getattr(
                        self.test_formatter_instance, '_current_section')
                self.test_formatter_instance.start_section(
                        scenario['test_heading_text'])
                self.assertEqual(
                        self.test_formatter_instance._current_section.parent,
                        expected_parent_section)


class ManPageHelpFormatter_format_actions_usage_TestCase(unittest.TestCase):
    """ Test cases for method `ManPageHelpFormatter._format_actions_usage`. """

    formatter_class = manpage.argparse_help.ManPageHelpFormatter
    parser_class = argparse.ArgumentParser

    scenarios = [
            ('simple', {
                'parser_actions': [
                    argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        ),
                    ],
                'group_params': [],
                'expected_result': "[\\fB\\-d\\fP \\fISPAM\\fP]",
                }),
            ('one-group', {
                'parser_actions': [
                    argparse.Action(
                        ["-d", "--dolor"],
                        dest="spam", metavar="SPAM",
                        ),
                    ],
                'group_params': [
                    {
                        'title': "Cras pretium",
                        'description': (
                            "Nulla vehicula pharetra fermentum."
                            " Nam porta mi sed nisl rhoncus tincidunt."),
                        'actions': [
                            argparse.Action(
                                ["-l", "--lacinia"],
                                dest="nisl", metavar="NISL",
                                ),
                            argparse.Action(
                                ["-s", "--suscipit"],
                                dest="enim", metavar="ENIM",
                                ),
                            ],
                        },
                    ],
                'expected_result': "[\\fB\\-d\\fP \\fISPAM\\fP]",
                }),
            ]

    def setUp(self):
        """ Set up test fixtures. """
        super().setUp()

        self.scenarios_by_name = dict(self.scenarios)

        setup_formatter_instance(self, test_args={
                'prog': "xyzzy",
                })

    def set_parser_instance(self, scenario):
        """ Set the ArgumentParser instance for the test scenario. """
        setup_parser_instance(
                self,
                test_args={},
                test_actions=scenario['parser_actions'])

    def make_action_groups(self, scenario):
        """ Make the action groups for the test scenario. """
        groups = []
        for params in scenario['group_params']:
            group = argparse._ArgumentGroup(
                    container=self.test_parser_instance,
                    title=params.get('title', None),
                    description=params.get('description', None))
            for action in params['actions']:
                group._add_action(action)
            groups.append(group)

        return groups

    def test_returns_expected_markup_text(self):
        """ Should return expected markup text. """
        for (scenario_name, scenario) in self.scenarios:
            with self.subTest(scenario=scenario_name):
                groups = self.make_action_groups(scenario)
                instance = self.test_formatter_instance
                self.set_parser_instance(scenario)
                test_args = {
                        'actions': scenario['parser_actions'],
                        'groups': groups,
                        }
                result = self.test_formatter_instance._format_actions_usage(
                        **test_args)
                self.assertEqual(result, scenario['expected_result'])


# This is free software: you may copy, modify, and/or distribute this work
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; version 3 of that license or any later version.
#
# No warranty expressed or implied. See the file ‘LICENSE.GPL-3’ for details,
# or view it online at <URL:https://www.gnu.org/licenses/gpl-3.0.html>.


# Local variables:
# coding: utf-8
# mode: python
# End:
# vim: fileencoding=utf-8 filetype=python :
